package org.elucid.gadmin.ui.events;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;

import org.apache.log4j.Logger;
import org.elucid.gadmin.GConnection;
import org.elucid.gadmin.ui.GDialog;
import org.elucid.gadmin.ui.GTableModel;

/**
 * 
 * @author george
 * 
 */
public class ExecuteActionListener implements ActionListener {

	private static Logger log = Logger.getLogger(ExecuteActionListener.class);
	private GDialog gDialog = null;

	/**
	 * 
	 * @param resultsPane
	 * @param serverInfo
	 * @param dbCombo
	 * @param text
	 */
	public ExecuteActionListener(GDialog gDialog) {
		super();
		this.gDialog = gDialog;

	}

	/**
	 * Update UI while query is executed
	 * 
	 * @author george
	 * 
	 */
	private class UpdateTask extends SwingWorker {

		public UpdateTask(GDialog gDialog) {
			super();
			this.setgDialog(gDialog);
		}

		private GDialog gDialog;

		@Override
		protected Void doInBackground() {

			long start = new Date().getTime();
			while (!isCancelled()) {
				long now = new Date().getTime();
				displayProgressText(String.format("%sms", now - start));
				try {
					Thread.sleep(17);
				} catch (InterruptedException e) {
				}
				Thread.yield();
			}

			return null;
		}

		public GDialog getgDialog() {
			return gDialog;
		}

		public void setgDialog(GDialog gDialog) {
			this.gDialog = gDialog;
		}
	}

	private class QueryTask extends SwingWorker {

		private UpdateTask updateTask;

		public QueryTask(UpdateTask updateTask) {
			this.updateTask = updateTask;
		}

		@Override
		protected Void doInBackground() {

			ResultSet results = null;
			Exception sqlError = null;
			try {

				GConnection conn;

				try {
					conn = new GConnection(gDialog.serverInfo);

					String databaseName = gDialog.dbCombo.getSelectedItem().toString();
					results = conn.query(gDialog.textpane.getText(), databaseName);

				} catch (SQLException e1) {
					sqlError = e1;
					e1.printStackTrace();
				} catch (Exception e1) {
					e1.printStackTrace();
				}

			} finally {
				gDialog.progress.setIndeterminate(false);
				updateTask.cancel(true);

				if (sqlError == null) {
					try {
						renderResults(results);
					} catch (Exception e) {
						e.printStackTrace();
					}
				} else {
					// JOptionPane.showMessageDialog(gDialog, sqlError.getMessage(), "SQL Error", JOptionPane.WARNING_MESSAGE);
					displayProgressText(sqlError.getMessage());
				}

			}
			return null;

		}

		/**
		 * 
		 * @param results
		 * @throws SQLException
		 */
		private void renderResults(ResultSet rs) throws SQLException {

			if (rs == null) // statement was not a Query
				return;

			List<List<Object>> rows = new ArrayList<List<Object>>();
			List<Integer> alignments = new LinkedList<Integer>();

			Object[][] data = { {} };
			List<String> columnNames = new ArrayList<String>();
			Object[] colNames = {};

			ResultSetMetaData rsmd = rs.getMetaData();

			int columns = rsmd.getColumnCount();
			for (int columnIndex = 1; columnIndex <= columns; columnIndex++) {
				String typeName = rsmd.getColumnTypeName(columnIndex);
				String columnName = String.format("<html><b>%s</b><br/>%s</html>", rsmd.getColumnName(columnIndex), typeName);
				columnNames.add(columnName);
				int columnType = rsmd.getColumnType(columnIndex);
				alignments.add(columnType == 12 ? JLabel.LEFT : JLabel.RIGHT);
			}

			while (rs.next()) {
				List<Object> row = new ArrayList<Object>();
				for (int columnIndex = 1; columnIndex <= columns; columnIndex++) {
					int columnType = rsmd.getColumnType(columnIndex);
					Object object = rs.getObject(columnIndex);
					if (columnType == 8) {
						object = String.format("%1$1.3f", object);
					}
					row.add(object);
				}
				rows.add(row);
			}

			if (rows.size() > 0) {
				data = new Object[rows.size()][rows.get(0).size() + 1];
				int rowIndex = 0;
				for (List<Object> row : rows) {
					Object[] array = row.toArray();
					data[rowIndex++] = array;
				}
				displayProgressText( String.format("%s; %s rows", gDialog.progressLabel.getText(), rowIndex) );
			}

			colNames = columnNames.toArray();

			final JTable table = new JTable(new GTableModel(data, colNames));
			table.getTableHeader().setPreferredSize(new Dimension(gDialog.getWidth(), 40));

			table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
			TableColumn column = null;
			for (int columnIndex = 0; columnIndex < table.getColumnModel().getColumnCount(); columnIndex++) {
				column = table.getColumnModel().getColumn(columnIndex);
				column.setWidth(100);
				column.setMinWidth(20);

				DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
				renderer.setHorizontalAlignment(alignments.get(columnIndex));
				table.getColumnModel().getColumn(columnIndex).setCellRenderer(renderer);
			}

			JScrollPane tableScrollPane = new JScrollPane(table);
			table.setFillsViewportHeight(true);

			gDialog.resultsPane.add(tableScrollPane);
			gDialog.resultsPane.doLayout();
		}
	}

	QueryTask queryTask = null;

	/**
	 * 
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		log.debug("actionPerformed");

		gDialog.resultsPane.removeAll();

		gDialog.progress.setIndeterminate(true);
		gDialog.invalidate();
		gDialog.repaint();

		UpdateTask updateTask = new UpdateTask(gDialog);
		updateTask.execute();
		queryTask = new QueryTask(updateTask);
		queryTask.execute();

	}

	public void displayProgressText(String text) {
		gDialog.progressLabel.setText(text);
	}

}
